package gang.org.springframework.framework.support;

import gang.org.springframework.framework.core.GangSerializableTypeWrapper;
import gang.org.springframework.framework.util.GangClassUtils;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * @author gang.chen
 * 封装一个JAVA类{@link Type},提供对Class类的各种访问操作
 * @Date 2021/6/15 18:46
 */
public class GangResolvableType implements Type,Serializable {

    private Class<?> resolved;
    private final Type type;

    //TODO
    private final Object typeProvider;
    //TODO
    private final Object variableResolver;
    //TODO
    private final Object componentType;
    //TODO
    private Integer hash;

    private GangResolvableType(Class<?> clazz){
        this.resolved = clazz;
        this.type = resolved;
        this.typeProvider = null;
        this.variableResolver = null;
        this.componentType = null;
    }

    public GangResolvableType(Type type, Object typeProvider, Object variableResolver, Object componentType) {
        this.type = type;
        this.typeProvider = typeProvider;
        this.variableResolver = variableResolver;
        this.componentType = componentType;
        this.hash = null;
        this.resolved = resolveClass();
    }

    public GangResolvableType(Type type, Object typeProvider, Object variableResolver, Integer hash){
        this.type = type;
        this.typeProvider = typeProvider;
        this.variableResolver = variableResolver;
        this.componentType = null;
        this.hash = hash;
        this.resolved = resolveClass();
    }

    //TODO
    public boolean isAssignableFrom(Class<?> other){
        return false;
    }


    public static GangResolvableType forRawClass(Class<?> clazz){
        return new GangResolvableType(clazz){
            @Override
            public boolean isAssignableFrom(Class<?> other) {
                /**
                 * clazz - > lhsType 接口
                 * other - > rhsType 实现类
                 * */
                return (clazz==null || GangClassUtils.isAssignable(clazz,other));
            }
        };
    }

    public Class<?> resolve(){
        return this.resolved;
    }

    public static GangResolvableType forClass(Class<?> clazz){
        return new GangResolvableType(clazz);
    }

    /**
     * 业务意义
     * 1）获取一个ResolvableType对象
     * @param method 方法对象
     * */
    public static GangResolvableType forMethodReturnType(Method method){
        return forMethodParameter(new GangMethodParameter(method, -1));
    }

    /**
     * 业务意义
     * 1）获取一个ResolvableType对象
     * @param methodParameter 参数对象
     * */
    private static GangResolvableType forMethodParameter(GangMethodParameter methodParameter) {
        return forMethodParameter(methodParameter, (Type)null);
    }

    /**
     * 业务意义
     * 1）获取一个ResolvableType对象
     * 2）当前业务场景下传入一个空对象
     * @param methodParameter 参数对象
     * @param target Type超级接口 value is null
     * */
    private static GangResolvableType forMethodParameter(GangMethodParameter methodParameter, Type target){
        return forMethodParameter(methodParameter, target, methodParameter.getNestingLevel());
    }

    /**
     * 业务意义
     * 1）构造方法重载
     * @param methodParameter 方法参数对象
     * @param target 超级接口value is null
     * @param nestingLevel value is 1
     * */
    private static GangResolvableType forMethodParameter(GangMethodParameter methodParameter, Type target, int nestingLevel){

        GangResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass());

        /**
         * 业务意义
         * target value is null
         * methodParameterTypeProvider 对methodParameter重新封装
         * */
        return forType(target, new GangSerializableTypeWrapper.GangMethodParameterTypeProvider(methodParameter), null).getNested(nestingLevel, null);
    }
    /**
     * 业务意义
     * @param type 方法返回对象 {@link gang.org.springframework.framework.web.servlet.config.annotation.GangWebMvcConfigurationSupport}
     * */
    public static GangResolvableType forType(Type type){
        return forType(type, null, null);
    }

    /**
     * 业务意义
     * @param type 方法返回对象 {@link gang.org.springframework.framework.web.servlet.config.annotation.GangWebMvcConfigurationSupport}
     * @param typeProvider structure by new
     * @param variableResolver value is null
     * */
    public static GangResolvableType forType(Type type, GangSerializableTypeWrapper.GangTypeProvider typeProvider, Object variableResolver){
        /**
         * 业务场景一，业务意义
         * 1）指定方法“mvcResourceUrlProvider”，返回的对象 GangResourceUrlProvider
         * */
        if (type == null && typeProvider != null) {
            /**
             * 业务意义
             * 1）获取方法返回的对象
             * */
            type = GangSerializableTypeWrapper.forTypeProvider(typeProvider);
        }

        //业务场景二

        //业务场景三
        if (type instanceof Class) {
            return new GangResolvableType(type, typeProvider, variableResolver, (GangResolvableType)null);
        }
        return null;
    }

    /**
     * 业务意义，方法返回对象
     * @param type {@link gang.org.springframework.framework.web.servlet.config.annotation.GangWebMvcConfigurationSupport}
     * */
    public GangResolvableType as(Class<?> type){
        /**
         * 场景一 TODO
         * */

        /**
         * 场景二 TODO
         * */
        Class<?> resolved = resolve();
        if (resolved == null || resolved == type) {
            return this;
        }

        /**
         * 场景三 TODO
         * */
        return null;
    }

    /**
     * 业务意义
     * */
    private Class<?> resolveClass(){
        //TODO 场景一

        //TODO 场景二

        //场景三
        if (this.type instanceof Class) {
            return (Class<?>) this.type;
        }
        return null;
    }

    /**
     * 业务意义
     * 1）创建一个空对象
     * */
    public static class EmptyType implements Type, Serializable{

        static final Type INSTANCE = new EmptyType();

        Object readResolve () {
            return INSTANCE;
        }
    }

    public GangResolvableType getNested(int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel){

        GangResolvableType result = this;

        /**
         * 业务场景一 TODO
         * 暂时不做业务考虑
         * */

        return result;
    }

    public boolean isInstance(Object obj){
        return obj != null && isAssignableFrom(obj.getClass());
    }


}
